package com.dragon.english_practice_back.controller;

import com.dragon.english_practice_back.controller.dto.MessageDTO;
import com.dragon.english_practice_back.advisor.TokenRecordAdvisor;
import com.dragon.english_practice_back.service.PromptRefineFactory;
import com.dragon.english_practice_back.service.impl.AuthenticationUtilImpl;
import com.dragon.english_practice_back.service.impl.MyChatMemory;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

@RestController
@AllArgsConstructor
@Slf4j
public class AIController {
    @Qualifier("deepSeekChatClient")
    private final ChatClient deepSeekChatClient;
    private final ObjectMapper objectMapper;
    private AuthenticationUtilImpl authenticationUtil;
    private MyChatMemory myChatMemory;
    private PromptRefineFactory promptRefineFactory;
    private TokenRecordAdvisor tokenRecordAdvisor;

    private final static String systemPrompt = """
                你是一名专业的英语对话练习伙伴，拥有丰富的英语教学经验和深厚的语言学知识。你的目标是帮助每位用户提高他们的英语口语能力，通过真实的对话场景和个性化的反馈来促进他们的语言学习。请记住以下几点：
                            
                1. **倾听与理解**：始终以开放的态度聆听用户的话语，展现出真诚的理解和支持。
                2. **提问而非直接给出答案**：通过提出开放式问题来鼓励用户表达更多信息，而不是立即提供答案或纠正错误。例如，“你觉得这句话应该怎么表达会更好？”、“你能分享一下你的想法吗？”等。
                3. **个性化反馈**：根据用户的回答和表现，提供具体的、建设性的反馈，帮助他们改进发音、语法和词汇使用。
                4. **引导性对话**：通过一系列引导性问题逐步深入对话，了解用户的兴趣、背景和学习目标，从而提供更个性化的练习内容。
                5. **文化融入**：在对话中融入英语国家的文化元素，帮助用户更好地理解和适应英语环境。
                6. **鼓励与激励**：始终保持积极的态度，鼓励用户不断进步，即使犯错也不要气馁。
                7. **持续学习**：不断更新自己的知识库，包括最新的英语教学方法、流行话题等方面的内容。
                            
                示例开场白：
                “Hello! I'm sasa, your English practice partner. I'm here to help you improve your English speaking skills through real conversations. Whether you're a beginner or an advanced learner, I'm here to support you. Let's start by getting to know each other a bit. Can you tell me about yourself and what you hope to achieve with your English learning?”
                            
                示例对话流程：
                1. **自我介绍**：
                   - “Hi there! My name is sasa. How about you? Could you introduce yourself?”
                  \s
                2. **了解用户背景**：
                   - “Where are you from? What do you like to do in your free time?”
                   - “Do you have any specific goals for learning English? Maybe for work, travel, or personal growth?”
                            
                3. **引导性问题**：
                   - “What topics do you enjoy talking about? We can focus on those to make our conversations more interesting.”
                   - “Have you ever visited an English-speaking country? If so, could you share some of your experiences?”
                            
                4. **具体练习**：
                   - “Let's practice a common conversation. Imagine we're at a coffee shop. You just ordered a latte. What would you say to the barista when they hand you your drink?”
                   - “Great job! Here’s a suggestion: Instead of saying ‘Thank you,’ you could also say ‘Thanks a lot’ or ‘Much appreciated.’ Try it out!”
                            
                5. **反馈与鼓励**：
                   - “You did really well! Your pronunciation is improving. Keep up the good work!”
                   - “If you want to sound more natural, try using contractions like ‘I’m’ instead of ‘I am.’”
                            
                ---
                            
                此预设旨在构建一种轻松、支持性的氛围，使用户感到被理解和接纳的同时，也能激发他们积极参与对话并不断提高英语水平。记得根据实际应用场景调整语言风格及具体内容哦！
                """;



    /**
     * 将流式回答结果转json字符串
     *
     * @param chatResponse 流式回答结果
     * @return String json字符串
     */
    @SneakyThrows
    public String toJson(ChatResponse chatResponse) {
        return objectMapper.writeValueAsString(chatResponse);
    }
    @PostMapping(value = "ai/PostSSEStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> postChatStream(@RequestBody MessageDTO input) {
        log.info("use AI stream userid: {} sessionId: {}", authenticationUtil.id(), input.getSessionId());

        // 插入不熟悉语法
        String systemPromptWithGraAndWord = promptRefineFactory.addGrammar(authenticationUtil.id(), systemPrompt);
        // 插入不熟悉单词
        systemPromptWithGraAndWord = promptRefineFactory.addStrangeWord(authenticationUtil.id(), systemPromptWithGraAndWord);
        // 构造系统消息
        Message systemMessage = new SystemMessage(systemPrompt);

        // 构造记忆器
        MessageChatMemoryAdvisor messageChatMemoryAdvisor =
                MessageChatMemoryAdvisor.builder(myChatMemory)
                        .conversationId(String.valueOf(input.getSessionId()))
                        .order(10)
                        .build();

        Flux<ServerSentEvent<String>> flux = null;
        flux = deepSeekChatClient.prompt()
                // 输入多条消息，可以将历史消息记录传入
                .messages(systemMessage,
                        new UserMessage(input.getMessage()))
                .advisors(messageChatMemoryAdvisor)
                .advisors(advisorSpec -> advisorSpec.param("service_user_id", authenticationUtil.id()))
                // 流式返回
                .stream()
                // 构造SSE（ServerSendEvent）格式返回结果
                .chatResponse()
                .map(chatResponse -> ServerSentEvent.builder(toJson(chatResponse))
                        .event("message")
                        .build())
                .onErrorResume(e -> {
                    log.error("AI访问出错: {}", e.getMessage());
                    return Flux.just(ServerSentEvent.builder("访问太频繁了")
                            .event("error")
                            .build());
                });
        return flux;
    }
    @PostMapping(value = "ai/deepseekStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> deepseekChatStream(@RequestBody MessageDTO messageDTO) {
        return deepSeekChatClient.prompt(messageDTO.getMessage()).stream().content();

    }

    
}
